/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package remotechessplayer;

import java.awt.Point;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.TimeLimitExceededException;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
 *
 * @author Jedrek
 */
public class RemoteChessPlayer extends SettingsPanel {

    static final byte ALLOW_MOVE = 1;
    static final byte FORBIT_MOVE = 2;
    static final byte THINKING = 4;
    static final byte NEW_MOVE = 8;
    static final byte YOU_ARE_THE_CHOSEN_ONE = 16;
    static final byte WHITE = 32;
    static final byte BLACK = 64;
    
    Socket socket = null;
    ServerSocket serverSocket = null;
    public boolean showAlerts = false;
    
    boolean makingMoveAllowed = false;
    
    public boolean isThinking = false;
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        RemoteChessPlayer player = new RemoteChessPlayer();
        
        JFrame frame = new JFrame("Settings panel");
        frame.setSize(player.getPreferredSize());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.add(player);
        frame.setVisible(true);
    }
    
    public RemoteChessPlayer(){
        super();
    }
    
    boolean submitConnection(){
        synchronized(this){
            if(workAsServer){
                serverSocket = serverPanel.serverSocket;
                socket = serverPanel.chosenSocket;
                if(socket == null || serverSocket == null)
                    return false;
                serverPanel.connected = true;
//                if(serverPanel.thread.isAlive())
//                    serverPanel.thread
            } else{
                socket = clientPanel.socket;
                if(socket == null)
                    return false;
                clientPanel.chosen = true;
            }
        }
        
        System.out.println("Connected to: "+socket.getInetAddress().getHostName()+" ("+socket.getInetAddress().getHostAddress()+")");
        return true;
    }
    
    public boolean isSubmitted(){
        synchronized(this){
            if(socket == null)
                return false;
            else
                return true;
        }
    }
    
    public void closeConnection(){
        
        if(socket != null && !socket.isClosed()){
            try{
                socket.close();
                socket = null;
                clientPanel.connected = false;
                clientPanel.socket = null;
                clientPanel.chosen = false;
                serverPanel.connected = false;
                serverPanel.chosenSocket = null;
            } catch(Exception e){
                if(showAlerts)
                    JOptionPane.showMessageDialog(null, "Couldn't close socket because: " + e.getMessage());
            }
        }
        if(serverSocket != null && !serverSocket.isClosed()){
            try{
                serverSocket.close();
                serverSocket = null;
            } catch(Exception e){
                if(showAlerts)
                    JOptionPane.showMessageDialog(null, "Couldn't close server socket because: " + e.getMessage());
            }
        }
    }
    
    public boolean setMove(Point from, Point to){
        OutputStream out;
        byte[] data;
        if(!isSubmitted())
            return false;
        synchronized(socket){
            try{
                out = socket.getOutputStream();
            } catch (IOException ex) {
                if(showAlerts)
                    JOptionPane.showMessageDialog(null, "Couldn't get OutputStream for socket because: " + ex.getMessage());
                return false;
            }
        }
            
        data = new byte[5];
        try{
            data[0] = NEW_MOVE;
            data[1] = (byte)from.x;
            data[2] = (byte)from.y;
            data[3] = (byte)to.x;
            data[4] = (byte)to.y;

            synchronized(socket){
                out.write(data);
            }
        } catch (IOException ex) {
            if(showAlerts)
                JOptionPane.showMessageDialog(null, "Couldn't communicate because: " + ex.getMessage());
            return false;
        }
        return true;
    }
    
    public boolean getMove(Point from, Point to){
        InputStream in;
        OutputStream out;
        int count;
        byte[] data;
        if(!isSubmitted())
            return false;
        
        synchronized(socket){
            try {
                in = socket.getInputStream();
            } catch (IOException ex) {
                if(showAlerts)
                    JOptionPane.showMessageDialog(null, "Couldn't get InputStream for socket because: " + ex.getMessage());
                return false;
            }
            try {
                out = socket.getOutputStream();
            } catch (IOException ex) {
                if(showAlerts)
                    JOptionPane.showMessageDialog(null, "Couldn't get OutputStream for socket because: " + ex.getMessage());
                return false;
            }
        }

        data = new byte[5];
        try{
//                data[0] = ALLOW_MOVE;
//                out.write(data);
            try{
                synchronized(socket){
                    count = in.read(data);
                }
                if(count < 0){
                    if(showAlerts)
                        JOptionPane.showMessageDialog(null, "Couldn't read data because Inputstream is closed (finished?)");
                    return false;
                }
            } catch(SocketTimeoutException ex){
                data[0] = 0;
            }

            while(data[0] != NEW_MOVE){
                if(data[0] == THINKING)
                    isThinking = true;
                try{
                    synchronized(socket){
                        count = in.read(data);
                    }
                    if(count < 0){
                        isThinking = false;
                        if(showAlerts)
                            JOptionPane.showMessageDialog(null, "Couldn't read data because Inputstream is closed (finished?)");
                        return false;
                    }
                } catch(SocketTimeoutException ex){
                    data[0] = 0;
                }
                Thread.sleep(10);
            }

            isThinking = false;
            from.x = (int)data[1];
            from.y = (int)data[2];
            to.x = (int)data[3];
            to.y = (int)data[4];
        } catch (Exception ex) {
            if(showAlerts)
                JOptionPane.showMessageDialog(null, "Couldn't communicate because: " + ex.getMessage());
            return false;
        }
        
        return true;
    }
    
    public boolean isConnectionValid(){
        int previousTimeout = 0;
        boolean result = true;
        synchronized(socket){
            try{
                previousTimeout = socket.getSoTimeout();
                socket.setSoTimeout(1);
                if(socket.getInputStream().read()<0){
                    result = false;
                }
            } catch(SocketTimeoutException ex){}
            catch (IOException ex){
                result = false;
            }
        }
        try {
            socket.setSoTimeout(previousTimeout);
        } catch (SocketException ex) {}
        
        return result;
    }
}
